/*
 * EmiChess.java
 *
 * EmiChess is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * EmiChess is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with the chess framework library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.frezell.chess;

import javax.swing.*;
import java.awt.*;
import java.net.URL;
import java.net.URLStreamHandlerFactory;
import java.net.URLStreamHandler;
import java.io.IOException;
import java.io.File;
import java.util.*;

import free.chess.*;
import free.jin.event.*;
import free.jin.board.PieceSet;
import free.jin.board.BoardManager;
import free.jin.*;
import free.jin.action.ActionInfo;
import free.jin.plugin.Plugin;
import free.jin.plugin.PluginInfo;
import free.util.zip.ZipURLStreamHandler;
import free.util.zip.ZipClassLoader;
import free.util.ExtensionFilenameFilter;
import free.util.IOUtilities;

/**
 * Short class description
 * <p/>
 * Long class description
 *
 * @author <a href="mailto:drew@frezell.org">Drew Frezell</a>
 * @version 0.0.1
 */
public class EmiChess implements GameListener, JinContext {
    private JFrame m_frame;
    private JBoard m_board;
    private BoardManager m_boardManager;
    private File m_prefsDir;

    private static final File JIN_DIR = new File(System.getProperty("user.dir"));

    static {
        URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
            public URLStreamHandler createURLStreamHandler(String protocol) {
                if (protocol.equals("zip"))
                    return new ZipURLStreamHandler();
                return null;
            }
        });
    }
    
    private void init() {
        Jin.createInstance(this);

        m_prefsDir = new File(".");

        m_boardManager = new BoardManager();
        
        PieceSet[] pset = getPieceSets();

        m_frame = new JFrame("EmiChess");
        m_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        m_frame.addWindowListener(new free.util.AppKiller());
        m_frame.getContentPane().setLayout(new BorderLayout());

        m_board = new JBoard();
        m_board.setMoveInputStyle(JBoard.CLICK_N_CLICK);
        m_board.setMoveInputMode(JBoard.CURRENT_PLAYER_MOVES);
        m_board.setCoordsDisplayStyle(JBoard.OUTSIDE_COORDS);
        m_board.setPreferredSize(new Dimension(400, 400));
        m_board.setPiecePainter(pset[2].getPiecePainter());

        for (int i = 0; i < pset.length; i++) {
            System.out.println("pset[" + i + "] = " + pset[i].toString());
        }

        m_frame.getContentPane().add(m_board, BorderLayout.CENTER);

        m_frame.pack();
        m_frame.setLocationRelativeTo(null);
    }

    public void setVisible(boolean vis) {
        m_frame.setVisible(vis);
    }

    private PieceSet[] getPieceSets() {
        Map<String, PieceSet> resources = m_boardManager.getResources("pieces");
        PieceSet[] pieceSets = resources.values().toArray(new PieceSet[resources.size()]);

        Collections.sort(Arrays.asList(pieceSets), new Comparator<PieceSet>() {
            public int compare(PieceSet set1, PieceSet set2) {
                return set1.getName().compareTo(set2.getName());
            }
        });

        return pieceSets;
    }

    /**
     * Loads resources from the specified directory, adding them to the
     * specified map. Helper method for <code>getResources</code>.
     * @param dir directory
     * @param resourceMap resource map
     * @param plugin plugin
     */
    private void loadResources(File dir, Map resourceMap, Plugin plugin) {
        if (!dir.exists() || !dir.isDirectory())
            return;

        String[] filenames = dir.list(new ExtensionFilenameFilter(".zip"));
        if (filenames == null)
            return;

        for (int i = 0; i < filenames.length; i++) {
            String filename = filenames[i];
            File resourceFile = new File(dir, filename);
            try {
                Resource resource = loadResource(resourceFile, plugin);

                if (resource != null)
                    resourceMap.put(resource.getId(), resource);
            } catch (IOException e) {
                System.out.println("Failed to load resource from " + resourceFile);
                e.printStackTrace();
            }
        }
    }

    /**
     * Loads a single resource from the specified file. Returns <code>null</code>
     * if unsuccessful. Helper method for <code>loadResources</code> and
     * <code>getResource</code>.
     * @param file file
     * @param plugin plugin
     * @throws IOException IO error
     * @return Resource
     */
    private Resource loadResource(File file, Plugin plugin) throws IOException {
        ZipClassLoader cl = new ZipClassLoader(file);
        Properties def = IOUtilities.loadPropertiesAndClose(cl.getResourceAsStream("definition"));
        if (def == null)
            return null;
        String classname = def.getProperty("classname");
        if (classname == null)
            return null;

        // Hack to support the old pieces/boards pack format.
        if ("ImagePieceSetLoader".equals(classname))
            classname = "free.jin.board.PieceSet";
        else if ("ImageBoardLoader".equals(classname))
            classname = "free.jin.board.BoardPattern";

        try {
            // We need to load it with the plugin's classloader because the
            // resource may be of a type which is a part of the plugin.
            Class resourceClass = plugin.getClass().getClassLoader().loadClass(classname);
            Resource resource = (Resource) resourceClass.newInstance();
            if (resource.load(cl.getResource("/"), plugin))
                return resource;
            else
                return null;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
        catch (InstantiationException e) {
            e.printStackTrace();
            return null;
        }
        catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * Main function
     * @param args command lin arguments to application
     */
    public static void main(String[] args) {
        EmiChess app = new EmiChess();
        app.init();
        app.setVisible(true);
    }

    // GameListener Interface methods
    public void gameStarted(GameStartEvent evt) {
    }

    public void moveMade(MoveMadeEvent evt) {
    }

    public void positionChanged(PositionChangedEvent evt) {
    }

    public void takebackOccurred(TakebackEvent evt) {
    }

    public void illegalMoveAttempted(IllegalMoveEvent evt) {
        System.out.println("illegal move : " + evt);
    }

    public void clockAdjusted(ClockAdjustmentEvent evt) {
    }

    public void boardFlipped(BoardFlipEvent evt) {
    }

    public void offerUpdated(OfferEvent evt) {
    }

    public void gameEnded(GameEndEvent evt) {
    }

    // JinContext Interface methods
    public Locale getLocale() {
        return null;
    }

    public String getParameter(String paramName) {
        return null;
    }

    public Preferences getPrefs() {
        return null;
    }

    public Map getResources(String resType, Plugin plugin) {
        Map resourceMap = new HashMap();

        File userResDir = new File(new File(m_prefsDir, "resources"), resType);
        File jinResDir = new File(new File(JIN_DIR, "resources"), resType);

        loadResources(jinResDir, resourceMap, plugin);
        loadResources(userResDir, resourceMap, plugin);

        return resourceMap;
    }

    public Resource getResource(String type, String id, Plugin plugin) {
        String serverId = plugin.getServer().getId();

        File userResDir = new File(new File(m_prefsDir, "resources"), type);
        File jinResDir = new File(new File(JIN_DIR, "resources"), type);
        File jinServerResDir = new File(new File(new File(JIN_DIR, "resources"), type), serverId);

        File[] files = new File[]{
                new File(userResDir, id + ".zip"),
                new File(jinServerResDir, id + ".zip"),
                new File(jinResDir, id + ".zip")
        };


        for (int i = 0; i < files.length; i++) {
            try {
                File file = files[i];
                if (file.exists())
                    return loadResource(file, plugin);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    public void shutdown() {
    }

    public Server[] getServers() {
        return new Server[0];
    }

    public User[] getUsers() {
        return new User[0];
    }

    public void setUsers(User[] users) {
    }

    public ActionInfo[] getActions(Server server) {
        return new ActionInfo[0];
    }

    public PluginInfo[] getPlugins(Server server) {
        return new PluginInfo[0];
    }

    public boolean isSavePrefsCapable() {
        return false;
    }

    public String getPasswordSaveWarning() {
        return null;
    }

    public boolean isUserExtensible() {
        return false;
    }
}

/* Modeline for ViM {{{
 * vim: set ts=4:
 * }}} */


